git操作

git三个分区

三个分区
三个分区之间的转换通过以上命令进行。工作区就是我们当前的文件目录。

阅读全文 »

Java面试题汇总

一、Java 基础

1.JDK 和 JRE 有什么区别?

答:

英文解释:

JRE: Java Runtime Environment。

JDK:Java Development Kit。

JRE顾名思义是java运行时环境,包含了java虚拟机,java基础类库。是使用java语言编写的程序运行所需要的软件环境,是提供给想运行java程序的用户使用的。

JDK顾名思义是java开发工具包,是程序员使用java语言编写java程序所需的开发工具包,是提供给程序员使用的。JDK包含了JRE,同时还包含了编译java源码的编译器javac,还包含了很多java程序调试和分析的工具:jconsole,jvisualvm等工具软件,还包含了java程序编写所需的文档和demo例子程序。

如果需要运行java程序,只需安装JRE就可以了。如果你需要编写java程序,需要安装JDK。

JRE根据不同操作系统(如:windows,linux等)和不同JRE提供商(IBM,ORACLE等)有很多版本,最常用的是Oracle公司收购SUN公司的JRE版本。

2.== 和 equals 的区别是什么?

答:

(1)==是判断两个变量或实例是不是指向同一个内存空间,equals是判断两个变量或实例所指向的内存空间的值是不是相同

(2)==是指对内存地址进行比较 , equals()是对字符串的内容进行比较

(3)==指引用是否相同, 并且equals()指的是值是否相同

3.两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?

答:

首先,答案肯定是不一定。同时反过来equals为true,hashCode也不一定相同。

类的hashCode方法和equals方法都可以重写,返回的值完全在于自己定义。

hashCode()返回该对象的哈希码值;equals()返回两个对象是否相等。

关于hashCode和equal是方法是有一些常规协定 :

(1)两个对象用equals()比较返回true,那么两个对象的hashCode()方法必须返回相同的结果。

(2)两个对象用equals()比较返回false,不要求hashCode()方法也一定返回不同的值,但是最好返回不同值,亿提搞哈希表性能。

(3)重写equals()方法,必须重写hashCode()方法,以保证equals方法相等时两个对象hashcode返回相同的值。

4.final 在 java 中有什么作用?

答:

final作为Java中的关键字可以用于三个地方。用于修饰类、类属性和类方法。

特征:凡是引用final关键字的地方皆不可修改!

(1)修饰类:表示该类不能被继承;

(2)修饰方法:表示方法不能被重写;

(3)修饰基本类型变量:表示变量只能一次赋值以后值不能被修改(常量)。

(4)修饰对象变量: 指向的对象不能修改, 但是对象本身的值可以修改.

5.java 中的 Math.round(-1.5) 等于多少?

答:

round函数是取最接近整数,如果遇到一样近,则取最大值。

因此Math.round(-1.5)=-1

6.String 属于基础的数据类型吗?

答:不属于

八大基本数据类型:byte、short、int、long、float、double、boolen、char

7.java 中操作字符串都有哪些类?它们之间有什么区别?

答:String、StringBuffer、StringBuilder

String :final修饰,String类的方法都是返回new String。即对String对象的任何改变都不影响到原对象,对字符串的修改操作都会生成新的对象。

StringBuffer :对字符串的操作的方法都加了synchronized,保证线程安全。

StringBuilder :不保证线程安全,在方法体内需要进行字符串的修改操作,可以new StringBuilder对象,调用StringBuilder对象的append、

8.String str="i"与 String str=new String(“i”)一样吗?

答:不一样

对于String str="i"来说:

(1) 在栈中创建str的引用。

(2) 去常量池中查看是否有相同Unicode编码的字符串常量。如果有将str指向该常量,如果没有则创建一个内容为”i”的字符串常量,将str的引用指向该常量。

(3) 如果str进行了赋值str= “ILY”,则栈中的str的引用指向新的内容为“ILY”的字符串常量。

对于String str=new String(“i”)来说:

在常量池中创建内容为“i”的对象,在堆中创建内容为“i”的对象。

9.如何将字符串反转?

答:

https://blog.csdn.net/cghu1201/article/details/78490934

第一种  通过String类的charAt()的方法来获取字符串中的每一个字符,然后将其拼接为一个新的字符串。

第二种   通过String的toCharArray()方法可以获得字符串中的每一个字符串并转换为字符数组,然后用一个空的字符串从后向前一个个的拼接成新的字符串。

第三种  通过StringBuiler的reverse()的方法,最快的方式。

第四种 通过递归的方式,其实有以上的就可以了,但是还是说一下递归,实在是应为这个感觉高大上一点而已。

10.String 类的常用方法都有那些?

答:

1、求字符串长度
public int length()//返回该字符串的长度

2、求字符串某一位置字符
public char charAt(int index)//返回字符串中指定位置的字符;注意字符串中第一个字符索引是0,最后一个是length()-1。

3、提取子串
用String类的substring方法可以提取字符串中的子串,该方法有两种常用参数:
1)public String substring(int beginIndex)//该方法从beginIndex位置起,从当前字符串中取出剩余的字符作为一个新的字符串返回。
2)public String substring(int beginIndex, int endIndex)//该方法从beginIndex位置起,从当前字符串中取出到endIndex-1位置的字符作为一个新的字符串返回。

4、字符串比较
1)public int compareTo(String anotherString)//该方法是对字符串内容按字典顺序进行大小比较,通过返回的整数值指明当前字符串与参数字符串的大小关系。若当前对象比参数大则返回正整数,反之返回负整数,相等返回0。
2)public int compareToIgnore(String anotherString)//与compareTo方法相似,但忽略大小写。
3)public boolean equals(Object anotherObject)//比较当前字符串和参数字符串,在两个字符串相等的时候返回true,否则返回false。
4)public boolean equalsIgnoreCase(String anotherString)//与equals方法相似,但忽略大小写。

5、字符串连接
public String concat(String str)//将参数中的字符串str连接到当前字符串的后面,效果等价于"+"。

6、字符串中单个字符查找
1)public int indexOf(int ch/String str)//用于查找当前字符串中字符或子串,返回字符或子串在当前字符串中从左边起首次出现的位置,若没有出现则返回-1。
2)public int indexOf(int ch/String str, int fromIndex)//改方法与第一种类似,区别在于该方法从fromIndex位置向后查找。
3)public int lastIndexOf(int ch/String str)//该方法与第一种类似,区别在于该方法从字符串的末尾位置向前查找。
4)public int lastIndexOf(int ch/String str, int fromIndex)//该方法与第二种方法类似,区别于该方法从fromIndex位置向前查找。

7、字符串中字符的大小写转换
1)public String toLowerCase()//返回将当前字符串中所有字符转换成小写后的新串
2)public String toUpperCase()//返回将当前字符串中所有字符转换成大写后的新串

8、字符串中字符的替换
1)public String replace(char oldChar, char newChar)//用字符newChar替换当前字符串中所有的oldChar字符,并返回一个新的字符串。
2)public String replaceFirst(String regex, String replacement)//该方法用字符replacement的内容替换当前字符串中遇到的第一个和字符串regex相匹配的子串,应将新的字符串返回。
3)public String replaceAll(String regex, String replacement)//该方法用字符replacement的内容替换当前字符串中遇到的所有和字符串regex相匹配的子串,应将新的字符串返回。

11.抽象类必须要有抽象方法吗?

答:抽象类可以没有抽象方法,但是如果一个类已经声明成了抽象类,即使这个类中没有抽象方法,它也不能再实例化,即不能直接构造一个该类的对象。
如果一个类中有了一个抽象方法,那么这个类必须声明为抽象类,否则编译通不过。

12.普通类和抽象类有哪些区别?

答:

1.抽象类不能被实例化。

2.抽象类可以有构造函数,抽象方法不能被声明为静态。

3.抽象方法只需申明,而无需实现,抽象类中可以允许普通方法有主体

4.含有抽象方法的类必须申明为抽象类

5.抽象的子类必须实现抽象类中所有抽象方法,否则这个子类也是抽象类。

13.抽象类能使用 final 修饰吗?

答:不能,抽象类是被用于继承的,final修饰代表不可修改、不可继承的。

14.接口和抽象类有什么区别?

答:https://www.cnblogs.com/jmyyyy/p/10960271.html

接口和抽象类有什么区别

他们都不能实例化对象,都可以包含抽象方法,而且抽象方法必须被继承的类全部实现。

区别:

(1)抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。

(2)抽象类要被子类继承,接口要被类实现。

(3)接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现

(4)接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。

(5)抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。

(6)抽象方法只能申明,不能实现,接口是设计的结果 ,抽象类是重构的结果

(7)抽象类里可以没有抽象方法

(8)如果一个类里有抽象方法,那么这个类只能是抽象类

(9)抽象方法要被实现,所以不能是静态的,也不能是私有的。

(10)接口可继承接口,并可多继承接口,但类只能单根继承。

15.java 中 IO 流分为几种?

答:

  1. 按照数据的流向:
    输入流、输出流
  2. 按照流数据的格式:
    字符流、字节流
  3. 按照流数据的包装过程:
    节点流(低级流)、处理流(高级流)

最基本的几种进行简单介绍:

•InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。

•OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。

图片

16.BIO、NIO、AIO 有什么区别?

答:

同步阻塞IO(BIO)

我们熟知的Socket编程就是BIO,一个socket连接一个处理线程(这个线程负责这个Socket连接的一系列数据传输操作)。阻塞的原因在于:操作系统允许的线程数量是有限的,多个socket申请与服务端建立连接时,服务端不能提供相应数量的处理线程,没有分配到处理线程的连接就会阻塞等待或被拒绝。

同步非阻塞IO(NIO)

New IO是对BIO的改进,基于Reactor模型。我们知道,一个socket连接只有在特定时候才会发生数据传输IO操作,大部分时间这个“数据通道”是空闲的,但还是占用着线程。NIO作出的改进就是“一个请求一个线程”,在连接到服务端的众多socket中,只有需要进行IO操作的才能获取服务端的处理线程进行IO。这样就不会因为线程不够用而限制了socket的接入。客户端的socket连接到服务端时,就会在事件分离器注册一个 IO请求事件 和 IO 事件处理器。在该连接发生IO请求时,IO事件处理器就会启动一个线程来处理这个IO请求,不断尝试获取系统的IO的使用权限,一旦成功(即:可以进行IO),则通知这个socket进行IO数据传输。

异步阻塞IO(AIO)

NIO是同步的IO,是因为程序需要IO操作时,必须获得了IO权限后亲自进行IO操作才能进行下一步操作。AIO是对NIO的改进(所以AIO又叫NIO.2),它是基于Proactor模型的。每个socket连接在事件分离器注册 IO完成事件 和 IO完成事件处理器。程序需要进行IO时,向分离器发出IO请求并把所用的Buffer区域告知分离器,分离器通知操作系统进行IO操作,操作系统自己不断尝试获取IO权限并进行IO操作(数据保存在Buffer区),操作完成后通知分离器;分离器检测到 IO完成事件,则激活 IO完成事件处理器,处理器会通知程序说“IO已完成”,程序知道后就直接从Buffer区进行数据的读写。

也就是说:AIO是发出IO请求后,由操作系统自己去获取IO权限并进行IO操作;NIO则是发出IO请求后,由线程不断尝试获取IO权限,获取到后通知应用程序自己进行IO操作。

17.Files的常用方法都有哪些?

答:https://www.cnblogs.com/wangjinlong-padan/p/6382924.html

Files.exists() 检测文件路径是否存在

Files.createFile()创建文件

Files.createDirectory()创建文件夹

Files.delete() 删除文件或者目录

Files.copy() 复制文件

Files.move() 移动文件

Files.size()查看文件个数

Files.read() 读取文件

Files.write()写入文件

18.JDBC与双亲委派与SPI

Java api中定义jdbc规范接口,厂商具体实现。

Class.forName(“com.mysql.jdbc.Driver”)能够完成MySql驱动注册的问题。因为forName会导致其中的 static代码被调用,从而间接调用了registerDriver,完成注册过程。

如果没有显示调用Class.forName则会在DriverManager.getConnection()中会调用ensureDriversInitialized(),这个函数中用了SPI的方式加载驱动。

1
2
3
4
5
6
7
8
9
AccessController.doPrivileged(new PrivilegedAction<Void>() {    
public Void run() {
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
Iterator<Driver> driversIterator = loadedDrivers.iterator(); try {
while (driversIterator.hasNext()) { driversIterator.next(); }
} catch (Throwable t) { // Do nothing
}
return null;
}

这个里面的ServiceLoader.load(Driver.class);中会使用线程上下文类加载器(就是当前线程是哪个类加载器就用哪个内加载器)。
然后在driversIterator.next();中实例化LazyClassPathLookupIterator()这个类,其中加载文件"META-INF/services/";这里面有class.forname()来加载。

图片

CommonClassLoader、CatalinaClassLoader、SharedClassLoader和WebappClassLoader则是Tomcat自己定义的类加载器,它们分别加载/common/、/server/、/shared/*(在tomcat 6之后已经合并到根目录下的lib目录下)和/WebApp/WEB-INF/*中的Java类库。其中WebApp类加载器和Jsp类加载器通常会存在多个实例,每一个Web应用程序对应一个WebApp类加载器,每一个JSP文件对应一个Jsp类加载器。

commonLoader:Tomcat最基本的类加载器,加载路径中的class可以被Tomcat容器本身以及各个Webapp(web应用)访问;

catalinaLoader:Tomcat容器私有的类加载器,加载路径中的class对于Webapp不可见;

sharedLoader:各个Webapp共享的类加载器,加载路径中的class对于所有Webapp可见,但是对于Tomcat容器不可见;

WebappClassLoader:各个Webapp私有的类加载器,加载路径中的class只对当前Webapp可见。

19.最大/小堆(java优先队列)

容量为64以下,以加倍扩容,大于64时,以50%扩容

20.java静态绑定与动态绑定

静态绑定(static binding):也叫前期绑定,在程序执行前,该方法就能够确定所在的类,此时由编译器或其它连接程序实现。

动态绑定(auto binding):也叫后期绑定,在运行时,虚拟机根据具体对象的类型进行绑定,或者说是只有对象在虚拟机中创建了之后,才能确定方法属于哪一个对象。多态。

分派感觉主要从方法表中方法分派的角度来说的,用分派来实现动态绑定。

二、容器

18.java 容器都有哪些?

答:

数组,String,java.util下的集合容器

数组长度限制为 Integer.Integer.MAX_VALUE;

String的长度限制: 底层是char 数组 长度 Integer.MAX_VALUE 线程安全的

List:存放有序,列表存储,元素可重复

Set:无序,元素不可重复

Map:无序,元素可重复

19.Collection 和 Collections 有什么区别?

答:

1、java.util.Collection 是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式。

List,Set,Queue接口都继承Collection。

直接实现该接口的类只有AbstractCollection类,该类也只是一个抽象类,提供了对集合类操作的一些基本实现。List和Set的具体实现类基本上都直接或间接的继承了该类。

2、java.util.Collections 是一个包装类。它包含有各种有关集合操作的静态方法(对集合的搜索、排序、线程安全化等),大多数方法都是用来处理线性表的。同时该类将构造函数定义为私有属性,因此该类不能被实例化,就像一个工具类,服务于Java的Collection框架。

20.List、Set、Map 之间的区别是什么?

答:

List的元素以线性方式存储,可以存放重复对象,List主要有以下两个实现类:

ArrayList : 长度可变的数组,可以对元素进行随机的访问,向ArrayList中插入与删除元素的速度慢。 JDK8 中ArrayList扩容的实现是通过grow()方法里使用语句newCapacity = oldCapacity + (oldCapacity >> 1)(即1.5倍扩容)计算容量,然后调用Arrays.copyof()方法进行对原数组进行复制。

LinkedList: 采用链表数据结构,插入和删除速度快,但访问速度慢。

Set中的对象不按特定(HashCode)的方式排序,并且没有重复对象,Set主要有以下两个实现类:

HashSet: HashSet按照哈希算法来存取集合中的对象,存取速度比较快。当HashSet中的元素个数超过数组大小*loadFactor(默认值为0.75)时,就会进行近似两倍扩容(newCapacity = (oldCapacity << 1) + 1)。

TreeSet :TreeSet实现了SortedSet接口,能够对集合中的对象进行排序。

Map是一种把键对象和值对象映射的集合,它的每一个元素都包含一个键对象和值对象。 Map主要有以下两个实现类:

HashMap:HashMap基于散列表实现,其插入和查询<K,V>的开销是固定的,可以通过构造器设置容量和负载因子来调整容器的性能。

LinkedHashMap:类似于HashMap,但是迭代遍历它时,取得<K,V>的顺序是其插入次序,或者是最近最少使用(LRU)的次序。

TreeMap:TreeMap基于红黑树实现。查看<K,V>时,它们会被排序。TreeMap是唯一的带有subMap()方法的Map,subMap()可以返回一个子树。

List 是可重复集合,Set 是不可重复集合,这两个接口都实现了 Collection 父接口。

Map 未继承 Collection,而是独立的接口,Map 是一种把键对象和值对象进行映射的集合,它的每一个元素都包含了一对键对象和值对象,Map 中存储的数据是没有顺序的, 其 key 是不能重复的,它的值是可以有重复的。

23.说一下 HashMap 的实现原理?

答:

在长度为length的数组中,每个元素存储的是一个链表的头结点的引用。这些元素按照既定的规则存储到数组中: 一般情况是通过hash(key)%length获得,也就是元素的key的哈希值对数组长度取余得到。根据对象的key获取HashCode值,用HashCode对length取余,得到存储位置index。

24.说一下 HashSet 的实现原理?

答:

①是基于HashMap实现的,默认构造函数是构建一个初始容量为16,负载因子为0.75 的HashMap。封装了一个 HashMap 对象来存储所有的集合元素,所有放入 HashSet 中的集合元素实际上由 HashMap 的 key 来保存,而 HashMap 的 value 则存储了一个 PRESENT,它是一个静态的 Object 对象。

②当我们试图把某个类的对象当成 HashMap的 key,或试图将这个类的对象放入 HashSet 中保存时,重写该类的equals(Object obj)方法和 hashCode() 方法很重要,而且这两个方法的返回值必须保持一致:当该类的两个的 hashCode() 返回值相同时,它们通过 equals() 方法比较也应该返回 true。通常来说,所有参与计算 hashCode() 返回值的关键属性,都应该用于作为 equals() 比较的标准。

③HashSet的其他操作都是基于HashMap的。

25.ArrayList 和 LinkedList 的区别是什么?

答:

ArrayList : 长度可变的数组,可以对元素进行随机的访问,向ArrayList中插入与删除元素的速度慢。 JDK8 中ArrayList扩容的实现是通过grow()方法里使用语句newCapacity = oldCapacity + (oldCapacity >> 1)(即1.5倍扩容)计算容量,然后调用Arrays.copyof()方法进行对原数组进行复制。

LinkedList: 采用链表数据结构,插入和删除速度快,但访问速度慢。

26.如何实现数组和 List 之间的转换?

答:

List转数组:toArray(arraylist.size()方法

数组转List:Arrays的asList(a)方法

27.ArrayList 和 Vector 的区别是什么?

答:

(1)同步性:Vector是线程安全的,用synchronized实现线程安全,而ArrayList是线程不安全的,如果只有一个线程会访问到集合,那最好使用ArrayList,因为它不考虑线程安全,效率会高些;如果有多个线程会访问到集合,那最好是使用Vector,因为不需要我们再去考虑和编写线程安全的代码。

(2)数据容量增长:二者都有一个初始容量大小,采用线性连续存储空间,当存储的元素的个数超过了容量时,就需要增加二者的存储空间,Vector增长原来的一倍,ArrayList增加原来的0.5倍。

28.Array 和 ArrayList 有何区别?

答:

(1)Array可以包含基本类型和对象类型,ArrayList只能包含对象类型。
Array大小是固定的,ArrayList的大小是动态变化的。

(2)ArrayList提供了更多的方法和特性,比如:addAll(), removeAll(),iterator()等等。
对于基本类型数据,集合使用自动装箱来减少编码工作量。但是,当处理固定大小的基本数据类型的时候,这种方式相对比较慢。

空间大小比较:

(一)它的空间大小是固定的,空间不够时也不能再次申请,所以需要事前确定合适的空间大小。

(二)ArrayList的空间是动态增长的,如果空间不够,它会创建一个空间比原空间大约0.5倍的新数组,然后将所有元素复制到新数组中,接着抛弃旧数组。而且,每次添加新的元素的时候都会检查内部数组的空间是否足够。(比较麻烦的地方)。

29.在Queue 中 poll()和 remove()有什么区别?

答:

Queue中remove()和poll()都是用来从队列头部删除一个元素,但是在poll()在队列为空时返回null,而remove()会抛出NoSuchElementException异常。

30.哪些集合类是线程安全的?

答:

(1)vector:就比arraylist多了个同步化机制(线程安全),因为效率较低,现在已经不太建议使用。在web应用中,特别是前台页面,往往效率(页面响应速度)是优先考虑的。

(2)statck:堆栈类,先进后出

(3)hashtable:就比hashmap多了个线程安全

(4)enumeration:枚举,相当于迭代器

(5)java.util.concurrent包下所有的集合类

ArrayBlockingQueue、ConcurrentHashMap、ConcurrentLinkedQueue、ConcurrentLinkedDeque…

31.迭代器 Iterator 是什么?

答:

Iterator接口提供了很多对集合元素进行迭代的方法。每一个集合类都包括了可以返回迭代器实例的迭代方法。迭代器可以在迭代过程中删除底层集合的元素,但是不可以直接调用集合的remove(Object obj)删除,可以通过迭代器的remove()方法删除

32.Iterator 怎么使用?有什么特点?

答:

图片

特点:

功能简单,并且能单向移动,对已集合类中的任何一个实现类,都可以返回这样一个Iterator对象。
使用方法 iterator()要求容器返回一个 Iterator。第一次调用Iterator 的next()方法时,它返回序列的第一个元素。
使用next()获得序列中的下一个元素。
使用hasNext()检查序列中是否还有元素。
使用remove()将上一次返回的元素从迭代器中移除。

33.Iterator 和 ListIterator 有什么区别?

答:

Iterator和ListIterator主要区别在以下方面:

(1)ListIterator有add()方法,可以向List中添加对象,而Iterator不能

(2)ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator就不可以。

(3)ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。

(4)都可实现删除对象,但是ListIterator可以实现对象的修改,set()方法可以实现。Iierator仅能遍历,不能修改。

因为ListIterator的这些功能,可以实现对LinkedList等List数据结构的操作。其实,数组对象也可以用迭代器来实现。

34.怎么确保一个集合不能被修改?

答:

可以采用Collections包下的unmodifiableMap方法,通过这个方法返回的map,是不可以修改的。会报 java.lang.UnsupportedOperationException错。

同理:Collections包也提供了对list和set集合的方法。
Collections.unmodifiableList(List)
Collections.unmodifiableSet(Set)

图片

三、多线程

35.并行和并发有什么区别?

答:

并发(concurrency)和并行(parallellism)是:

解释一:并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生。

解释二:并行是在不同实体上的多个事件,并发是在同一实体上的多个事件。

解释三:在一台处理器上“同时”处理多个任务,在多台处理器上同时处理多个任务。如hadoop分布式集群

36.线程和进程的区别?

答:

线程是程序执行时的最小单位,它是进程的一个执行流,是CPU调度和分派的基本单位,一个进程可以由很多个线程组成,线程间共享进程的所有资源,每个线程有自己的堆栈和局部变量。线程由CPU独立调度执行,在多CPU环境下就允许多个线程同时运行。同样多线程也可以实现并发操作,每个请求分配一个线程来处理。

线程和进程的区别

(1)进程是资源分配的最小单位,线程是程序执行的最小单位。

(2)进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。而线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多。

(3)线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点。

(4)但是多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。

37.守护线程是什么?

答:

守护线程,专门用于服务其他的线程,如果其他的线程(即用户自定义线程)都执行完毕,连main线程也执行完毕,那么jvm就会退出(即停止运行)——此时,连jvm都停止运行了,守护线程当然也就停止执行了。

38.创建线程有哪几种方式?

答:

(一)继承Thread类,然后调用start方法。

图片

(二)实现Runnable接口的run方法,然后再用Thread类包裹后,调用start方法。

图片

(三)实现Callable接口的call方法,用FutureTask类包裹Callable对象。然后再用Thread类包裹FutureTask类,并调用start方法。call()方法可以有返回值。

图片

39.说一下 runnable 和 callable 有什么区别?

答:

相同点:

两者都是接口;(废话)

两者都可用来编写多线程程序;

两者都需要调用Thread.start()启动线程;

不同点:

两者最大的不同点是:实现Callable接口的任务线程能返回执行结果;而实现Runnable接口的任务线程不能返回结果;

Callable接口的call()方法允许抛出异常;而Runnable接口的run()方法的异常只能在内部消化,不能继续上抛;

8.java线程有哪些状态?

![图片](data:image/jpg;base64,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)

41.sleep() 和 wait() 有什么区别?

答:

**1、**每个对象都有一个锁来控制同步访问,Synchronized关键字可以和对象的锁交互,来实现同步方法或同步块。sleep()方法正在执行的线程主动让出CPU(然后CPU就可以去执行其他任务),在sleep指定时间后CPU再回到该线程继续往下执行(注意:sleep方法只让出了CPU,而并不会释放同步资源锁!!!);wait()方法则是指当前线程让自己暂时退让出同步资源锁,以便其他正在等待该资源的线程得到该资源进而运行,只有调用了notify()方法,之前调用wait()的线程才会解除wait状态,可以去参与竞争同步资源锁,进而得到执行。(注意:notify的作用相当于叫醒睡着的人,而并不会给他分配任务,就是说notify只是让之前调用wait的线程有权利重新参与线程的调度);

2、sleep()方法可以在任何地方使用;wait()方法则只能在同步方法或同步块中使用;

**3、sleep()**是线程线程类(Thread)的方法,调用会暂停此线程指定的时间,但监控依然保持,不会释放对象锁,到时间自动恢复;**wait()**是Object的方法,调用会放弃对象锁,进入等待队列,待调用notify()/notifyAll()唤醒指定的线程或者所有线程,才会进入锁池,再次获得对象锁才会进入运行状态;

42.notify()和 notifyAll()有什么区别?

答:

如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁。

当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。也就是说,调用了notify后只要一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争

优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用 wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。

43.线程的 run()和 start()有什么区别?

答:

每个线程都有要执行的任务。线程的任务处理逻辑可以在Tread类的run实例方法中直接实现或通过该方法进行调用,因此

run()相当于线程的任务处理逻辑的入口方法,它由Java虚拟机在运行相应线程时直接调用,而不是由应用代码进行调用。

而start()的作用是启动相应的线程。启动一个线程实际是请求Java虚拟机运行相应的线程,而这个线程何时能够运行是由线程调度器决定的。start()调用结束并不表示相应线程已经开始运行,这个线程可能稍后运行,也可能永远也不会运行。

run():不管是通过实现Runnable接口还是继承Thread类(其实Thread中的run方法也是调用了Runnable接口的run方法),调用run()方法仅仅是相当于调用了一个方法,没有启用新的线程。

start():会启动一个新线程,运行重写的run()代码。

44.创建线程池有哪几种方式?

答:

newSingleThreadExecutor

创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

newFixedThreadPool

创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。

newCachedThreadPool

创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,

那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。

newScheduledThreadPool

创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。

45.线程池都有哪些状态?

答:

线程池的5种状态:Running、ShutDown、Stop、Tidying、Terminated。

1、RUNNING

(1) 状态说明:线程池处在RUNNING状态时,能够接收新任务,以及对已添加的任务进行处理。

(02) 状态切换:线程池的初始化状态是RUNNING。换句话说,线程池被一旦被创建,就处于RUNNING状态,并且线程池中的任务数为0!

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

1

2、 SHUTDOWN

(1) 状态说明:线程池处在SHUTDOWN状态时,不接收新任务,但能处理已添加的任务。

(2) 状态切换:调用线程池的shutdown()接口时,线程池由RUNNING -> SHUTDOWN。

3、STOP

(1) 状态说明:线程池处在STOP状态时,不接收新任务,不处理已添加的任务,并且会中断正在处理的任务。

(2) 状态切换:调用线程池的shutdownNow()接口时,线程池由(RUNNING or SHUTDOWN ) -> STOP。

4、TIDYING

(1) 状态说明:当所有的任务已终止,ctl记录的”任务数量”为0,线程池会变为TIDYING状态。当线程池变为TIDYING状态时,会执行钩子函数terminated()。terminated()在ThreadPoolExecutor类中是空的,若用户想在线程池变为TIDYING时,进行相应的处理;可以通过重载terminated()函数来实现。

(2) 状态切换:当线程池在SHUTDOWN状态下,阻塞队列为空并且线程池中执行的任务也为空时,就会由 SHUTDOWN -> TIDYING。

当线程池在STOP状态下,线程池中执行的任务为空时,就会由STOP -> TIDYING。

5、 TERMINATED

(1) 状态说明:线程池彻底终止,就变成TERMINATED状态。

(2) 状态切换:线程池处在TIDYING状态时,执行完terminated()之后,就会由 TIDYING -> TERMINATED。

46.线程池中 submit()和 execute()方法有什么区别?

答:

线程池中的execute方法,即开启线程执行池中的任务。还有一个方法submit也可以做到,它的功能是提交指定的任务去执行并且返回Future对象,即执行的结果。Submit内部调用execute()

  1. 接收的参数不一样

2、返回值不一样

submit有返回值Future,而execute没有。

3、submit方便Exception处理

47.在 java 程序中怎么保证多线程的运行安全?

答:

JDK Atomic开头的原子类、synchronized、LOCK,可以解决原子性问题

synchronized、volatile、LOCK,可以解决可见性问题

Happens-Before 规则可以解决有序性问题

48.多线程锁的升级原理是什么?

答:

锁的级别:

无锁->偏向锁->轻量级锁->重量级锁

锁分级别原因:

没有优化前,sychroniezed是重量级锁(悲观锁),使用wait、notify、notifyAll来切换线程状态非常消耗系统资源,线程的挂起和唤醒间隔很短暂,这样很浪费资源,影响性能。所以JVM对sychronized关键字进行了优化,把锁分为无锁、偏向锁、轻量级锁、重量级锁。

一、无锁

没有对资源进行锁定,所有的线程都能访问并修改同一个资源,但同时只有一个线程能修改成功,其它修改失败的线程会不断重试直到修改成功。

二、偏向锁

对象的代码一直被同一线程执行,不存在多个线程竞争,该线程在后续执行中自动获取锁,降低获取锁带来的性能开销。偏向锁,指的是偏向第一个加锁线程,该线程是不会主动释放偏向锁的,只有当其他线程尝试竞争偏向锁才会被释放。

偏向锁的撤销,需要在某个时间点上没有字节码正在执行时,先暂停偏向锁的线程,然后判断锁对象是否处于被锁定状态,如果线程不处于活动状态,则将对象头设置成无锁状态,并撤销偏向锁。

如果线程处于活动状态,升级为轻量级锁的状态。

三、轻量级锁

轻量级锁是指当锁是偏向锁的时候,被第二个线程B访问,此时偏向锁就会升级为轻量级锁,线程B会通过自旋的形式尝试获取锁,线程不会阻塞,从未提升性能。

当前只有一个等待线程,则该线程将通过自旋进行等待。但是当自旋超过一定次数时,轻量级锁边会升级为重量级锁,当一个线程已持有锁,另一个线程在自旋,而此时第三个线程来访时,轻量级锁也会升级为重量级锁。

注:自旋是什么?

自旋(spinlock)是指当一个线程获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。

四、重量级锁

指当有一个线程获取锁之后,其余所有等待获取该锁的线程都会处于阻塞状态。

重量级锁通过对象内部的监听器(monitor)实现,而其中monitor的本质是依赖于底层操作系统的Mutex Lock实现,操作系统实现线程之间的切换需要从用户态切换到内核态,切换成本非常高。

49.什么是死锁?

答:

线程死锁是指由于两个或者多个线程互相持有对方所需要的资源,导致这些线程处于等待状态,无法前往执行。当线程进入对象的synchronized代码块时,便占有了资源,直到它退出该代码块或者调用wait方法,才释放资源,在此期间,其他线程将不能进入该代码块。当线程互相持有对方所需要的资源时,会互相等待对方释放资源,如果线程都不主动释放所占有的资源,将产生死锁。

50.怎么防止死锁?

答:

(1)避免多次锁定。尽量避免同一个线程对多个 Lock 进行锁定。例如上面的死锁程序,主线程要对 A、B 两个对象的 Lock 进行锁定,副线程也要对 A、B 两个对象的 Lock 进行锁定,这就埋下了导致死锁的隐患。

(2)具有相同的加锁顺序。如果多个线程需要对多个 Lock 进行锁定,则应该保证它们以相同的顺序请求加锁。比如上面的死锁程序,主线程先对 A 对象的 Lock 加锁,再对 B 对象的 Lock 加锁;而副线程则先对 B 对象的 Lock 加锁,再对 A 对象的 Lock 加锁。这种加锁顺序很容易形成嵌套锁定,进而导致死锁。如果让主线程、副线程按照相同的顺序加锁,就可以避免这个问题。

(3)使用定时锁。程序在调用 acquire() 方法加锁时可指定 timeout 参数,该参数指定超过 timeout 秒后会自动释放对 Lock 的锁定,这样就可以解开死锁了。

(4)死锁检测。死锁检测是一种依靠算法机制来实现的死锁预防机制,它主要是针对那些不可能实现按序加锁,也不能使用定时锁的场景的。

51.ThreadLocal 是什么?有哪些使用场景?

答:

ThreadLocal 是线程本地存储,在每个线程中都创建了一个 ThreadLocalMap 对象,每个线程可以访问自己内部 ThreadLocalMap 对象内的 value。

经典的使用场景是为每个线程分配一个 JDBC 连接 Connection。这样就可以保证每个线程的都在各自的 Connection 上进行数据库的操作,不会出现 A 线程关了 B线程正在使用的 Connection; 还有 Session 管理 等问题。

52.说一下 synchronized 底层实现原理?

答:

从JVM规范中可以看到Synchronized在JVM里的实现原理,JVM基于进入和退出Monitor对象来实现方法同步和代码块同步。monitorenter指令是在编译后插入到同步代码块的开始位置,而monitorexit是插入到方法结束处和异常处,JVM要保证每个monitorenter必须有对应的monitorexit与之配对。任何对象都有一个monitor与之关联,当且一个monitor被持有后,它将处于锁定状态。线程执行到monitorenter指令时,将会尝试获取对象所对应的monitor的所有权,即尝试获得对象的锁。

53.synchronized 和 volatile 的区别是什么?

答:

  • volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
  • volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的
  • volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性
  • volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
  • volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化

54.synchronized 和 Lock 有什么区别?

答:

(1)首先synchronized是java内置关键字,在jvm层面,Lock是个java类;

(2)synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;

(3)synchronized会自动释放锁(a 线程执行完同步代码会释放锁 ;b 线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁;

(4)用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;

(5)synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可)

(6)Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。

55.synchronized 和 ReentrantLock 区别是什么?

答:

1.相比synchronized,ReentrantLock(重入锁)增加了一些高级功能

等待可中断——对于synchronized,如果一个线程正在等待锁,那么结果只有两种情况,要么获得这把锁继续执行 ,要么就保持等待。而使用ReentrantLock,如果一个线程正在等待锁,那么它依然可以收到通知,被告知无需再等待,可以停止工作了。

1)lockInterruptiby()的使用:

线程t1一直占用者锁 不释放,此时t2一直在等待着锁,通过lockInterruptibly()方法可以通知线程t2停止等待,而使用synchronized方式,只能继续等待。注意:这里说的是一个线程正在等待锁即没有获得锁的情况,而不是说获得锁后执行出行异常,这两者不一样,因为synchronized同步的代码出现异常,也会释放锁,例如在synchronized同步代码中进入sleep(),此时通过中断,也会释放锁。

2)使用tryLock进行尝试锁定,不管锁定与否,方法都将继续执行,可以根据tryLock的返回值来判定是否锁定

也可以指定tryLock的时间,犹如tryLock(time)抛出异常,所以要注意unlock的处理,必须方法finally中。

2.可实现公平锁:公平锁是指多个线程在等待同一个锁时,必须按照申请锁的时间顺序来依次获得锁,而非公平锁不保证这一点,在锁被释放时,任何一个等待锁的线程都有机会获得锁,synchronized中的锁是非公平的,ReenrantLock默认情况下也是非公平的,但是可以在构造函数中设置为公平锁。ReentrantLock(boolean fair) 。

3.锁可以绑定多个条件

一个ReentrantLock对象可以同时绑定多个Condition(即对象监视器)实例,线程对象可以注册在指定的Condition中,从而可以有选择性地进行线程通知。

自己对condtion的理解:condition使得调用该方法的线程进入等待队列,但是唤醒的时候唤醒的是对方的等待队列。用一个例子来说明,有一个容器,有多个生产者和多个消费者,希望当容器满的时候,能够只让生产的线程等待,只唤醒消费的线程,同样当容器空的时候,让消费的线程等待,只唤醒生产的线程。

4.线程阻塞在进入synchronized关键字修饰的方法或代码块(获取锁)时的状态称为阻塞状态。但是阻塞在Lock接口的线程状态却是等待状态,因为Lock接口对于阻塞的实现均使用了LockSupport类中的相关方法。

56.说一下 atomic 的原理?

答:

可以看到大概实现原理是:通过CAS乐观锁保证原子性,通过自旋保证当次修改的最终修改成功,通过**降低锁粒度(多段锁)**增加并发性能。

9.LockSupport

在AQS中,就是通过调用LockSupport.park( )和LockSupport.unpark()来实现线程的阻塞和唤醒的。

LockSupport.park()阻塞当前线程,LockSupport.unpark(Thread t )唤醒指定的t线程。thread.interrupt();起到和unpark()一样的作用。

使用LockSupport先唤醒线程,在阻塞线程,线程不会真的阻塞;但是先唤醒线程两次再阻塞两次时就会导致线程真的阻塞。

这个凭证(_counter)最多只有1个。当调用park方法时,如果有凭证,则会直接消耗掉这个凭证然后正常退出;但是如果没有凭证,就必须阻塞等待凭证可用;而unpark则相反,它会增加一个凭证,但凭证最多只能有1个。

因为凭证(_counter)的数量最多为1,连续调用两次unpark和调用一次unpark效果一样,只会增加一个凭证;而调用两次park却需要消费两个凭证。

四、反射

1.什么是反射?

答:

JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

2.什么是 java 序列化?什么情况下需要序列化?

答:

序列化:将 Java 对象转换成字节流的过程。

序列化情况:当 Java 对象需要在网络上传输 或者 持久化存储到文件中时,就需要对 Java 对象进行序列化处理。

3.动态代理是什么?有哪些应用?

答:

动态代理:在运行时,创建目标类,可以调用和扩展目标类的方法。

应用场景如:

  • 统计每个 api 的请求耗时
  • 统一的日志输出
  • 校验被调用的 api 是否已经登录和权限鉴定
  • Spring的 AOP 功能模块就是采用动态代理的机制来实现切面编程

4.怎么实现动态代理?

答:

java领域中,常用的动态代理实现方式有两种,一种是利用****JDK反射机制生成代理,另外一种是使用CGLIB代理。

5.CGLib

CGLib可以代理类和接口,final类和方法不能被代理,特别说明private的方法也不能代理。

五、JVM

1.GC时机

Full GC时机

一:代码中调用System.gc()方法会建议JVM进行Full GC;

二:Survivor区域的对象满足晋升到老年代的条件时,晋升进入老年代的对象大小大于老年代的可用内存,这个时候会触发Full GC;

三: Metaspace使用的是本地内存,-XX:MetaspaceSize=21810376B(约为20.8MB)超过这个值就会引发Full GC,这个值不是固定的,是会随着JVM的运行进行动态调整的。

四:老年代没有做足够的连续空间来放置大对象,那么就会引起Full GC。

五:统计得到的之前Minor GC晋升到老年代的对象的平均大小大于老年代的剩余空间,那么这一次Minor GC直接使用Full GC。

Minor GC时机:

触发原因都是eden区满了。

2.GC 分析

可达性分析:

从GC Roots开始搜索,搜索和这些节点发生直接或者间接引用关系的对象,以链的形式组合起来,形成引用链。

GC Roots: 1:栈帧中的引用对象。(栈中的)2:静态属性引用的对象。(方法区中的)3:常量引用的对象。(方法区中的)4:本地方法栈中JNI引用的对象。(本地方法栈中的)

完全回收一个对象,至少需要经过两次标记的过程。

第一次标记:对于一个没有其他引用的对象,筛选该对象是否有必要执行finalize()方法,如果没有执行必要,则意味可直接回收。(筛选依据:是否复写或执行过finalize()方法;因为finalize方法只能被执行一次)。

第二次标记:如果被筛选判定位有必要执行,则会放入FQueue队列,并自动创建一个低优先级的finalize线程来执行释放操作。如果在一个对象释放前被其了 他对象引用,则该对象会被移除FQueue队列。

3.GC算法和收集器

算法主要包括:标记-复制,标记-清除,标记-整理。

收集器:年轻代:Serial parNew Parllel 老年代:Serial Old,Parllel Old CMS. G1都可以。

ZGC:不支持32位指针也不支持压缩指针。

图片

Marked0/marked1: 判断对象是否已标记

Remapped: 判断应用是否已指向新的地址

Finalizable: 判断对象是否只能被Finalizer访问

G1一开始就把堆划分成固定大小的Region,而ZGC 可以有2MB,32MB,N× 2MB 三种Size Groups,动态地创建和销毁Region,动态地决定Region的大小。

4.java类加载过程

图片

5.JVM命令

查看gc日志 jdk8 -XX:+PrintGCDetails jdk11 -Xlog:gc*.

六、MySQL

1.MySQL索引类型

1.普通索引index

2.唯一索引unique

3.主键索引

4.组合索引

5.全文索引fulltext

组合索引中(x,y)中,x在前时,单独查询x会走索引,单独查询y不会走索引。组合索引将区分度高的字段放在前面,区分度低的字段放后面。

组合索引 最左匹配原则,在遇到范围查询的时候,就会停止匹配。如果索引是(a,b)那么(a>2 and b=2)a就用索引,b不用。如果索引是(b,a)就会使用索引。

非聚集索引,分成普通索引,唯一索引,全文索引。

图片

2.聚集 索引和非聚集索引

https://blog.csdn.net/b_x_p/article/details/86434387非常详细的mysql索引介绍。

聚集索引,叶子节点存的是整行数据,直接通过这个聚集索引的键值找到某行;数据的物理存放顺序与索引顺序是一致的,即:只要索引是相邻的,那么对应的数据一定也是相邻地存放在磁盘上的。一个表只能有一个聚集索引。

非聚集索引,叶子节点存的是字段的值,通过这个非聚集索引的键找到对应的聚集索引字段的值,再通过聚集索引键值找到表的某行。

拼音检索就是聚集索引,因为存储的记录(数据库中是行数据、字典中是汉字的详情记录)是按照该索引排序的;笔画索引,虽然笔画相同的字在笔画索引中相邻,但是实际存储页码却不相邻,这是非聚集索引。

非聚集索引不一定要回表这个过程,因为能找到非聚集索引的key和主键key,如果就是找这两个值直接可以找到了。

3. MyISAM与InnoDB 的区别

  1. InnoDB支持事务,MyISAM不支持,对于InnoDB每一条SQL语言都默认封装成事务,自动提交,这样会影响速度,所以最好把多条SQL语言放在begin和commit之间,组成一个事务;

  2. InnoDB支持外键,而MyISAM不支持。对一个包含外键的InnoDB表转为MYISAM会失败;

  3. InnoDB是聚集索引,使用B+Tree作为索引结构,数据文件是和(主键)索引绑在一起的(表数据文件本身就是按B+Tree组织的一个索引结构),必须要有主键,通过主键索引效率很高。但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。因此,主键不应该过大,因为主键太大,其他索引也都会很大。MyISAM是非聚集索引,也是使用B+Tree作为索引结构,索引和数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。

  4. InnoDB支持表、行(默认)级锁,而MyISAM支持表级锁。

4.mysql架构图

图片

5. inndb的B+树的高度为什么一般只有3层

我们假设主键 ID 为 bigint 类型,长度为 8 字节,而指针大小在 InnoDB 源码中设置为 6 字节,这样一共 14 字节,我们一个页中能存放多少这样的单元,其实就代表有多少指针,即 16384/14=1170。

那么可以算出一棵高度为 2 的 B+ 树,能存放 1170*16=18720 条这样的数据记录。

根据同样的原理我们可以算出一个高度为 3 的 B+ 树可以存放: 1170117016=21902400 条这样的记录

单个叶子节点(页)中的记录数 =16K/1K=16。

所以在 InnoDB 中 B+ 树高度一般为 1-3 层,它就能满足千万级的数据存储。

在查找数据时一次页的查找代表一次 IO,所以通过主键索引查询通常只需要 1-3 次 IO 操作即可查找到数据。

6.InnoDB中MVCC的实现

图片

https://blog.csdn.net/SnailMann/article/details/94724197讲解MVCC的博客

7.redo log和binlog

redo日志缓存刷入redo日志文件的时机:1、定期(master线程做); 2、每个事务提交时,就会触发redo日志缓存刷入,及时将该事务的redo日志存入磁盘;3、当redo日志缓存空间剩余不到1/2时,也会触发。

binlog 用于存储对数据库的所有改动sql,存的sql级别的,而且是所有的,而 redo 日志记录的是物理内存级别上的修改,更加底层。

七、数据结构

1.红黑树

红黑树定义:

根节点是黑色。

每个叶子节点(NIL)是空的黑色。

每个红色结点的两个子结点一定都是黑色。

任意一结点到每个叶子结点的路径都包含数量相同的黑结点。

红黑树能自平衡,它靠的是三种操作:左旋、右旋和变色。

左旋:以某个结点作为支点(旋转结点),其右子结点变为旋转结点的父结点,右子结点的左子结点变为旋转结点的右子结点,左子结点保持不变。

右旋:以某个结点作为支点(旋转结点),其左子结点变为旋转结点的父结点,左子结点的右子结点变为旋转结点的左子结点,右子结点保持不变。

黑色完美平衡二叉查找树,查找最坏时间复杂度为O(2lgN)。

插入情景1:红黑树为空树。

直接把插入结点作为根结点就行,根据红黑树性质2:根节点是黑色。还需要把插入结点设为黑色。

插入情景2:插入结点的Key已存在

把插入结点设置为将要替代结点的颜色,再把结点的值更新就完成插入。

插入情景3:插入结点的父结点为黑结点

插入的结点是红色的,并不会影响红黑树的平衡,直接插入即可,无需做自平衡。

插入情景4:插入结点的父结点为红结点

红黑树的删除,就是找一个替换节点(一般是右子树的最左0节点)来替换删除的节点。

删除情景1:替换结点是红色结点

替换结点是红色,删除也了不会影响红黑树的平衡,只要把替换结点的颜色设为删除的结点的颜色即可重新平衡。

删除情景2:替换结点是黑结点

八、操作系统

1.Linux IO模型

图片

IO模型组合图如上。

同步阻塞IO

图片

同步非阻塞IO

图片

IO多路复用(同步阻塞模式)

图片

信号驱动IO(同步非阻塞IO)

图片

异步非阻塞IO

图片

2. select、poll、epoll详解

为了保证内核的安全,处于用户态的程序只能访问用户空间,而处于内核态的程序可以访问用户空间和内核空间。

Linux将所有设备都当做文件来处理,文件描述符来标识每个文件对象。

IO多路复用——基本原理就是select,poll,epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。

当select函数返回后,只是说明有描述符准备好了,还需要可以遍历描述符,找到就绪的描述符。

select的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,可以通过修改宏定义的方式提升这一限制。

poll没有最大限制(但是数量过大后性能也是会下降)。和select函数一样,poll返回后,需要轮询来获取就绪的描述符。

epoll更加灵活,没有描述符限制。epoll通过注册事件回调。

使用mmap加速内核与用户空间的消息传递。

select缺点:

最大并发数限制:使用32个整数的32位,一个位数组,即32*32=1024来标识fd,虽然可修改,但是有以下第二点的瓶颈;

效率低:每次都会线性扫描整个fd_set,集合越大速度越慢;

内核/用户空间内存拷贝问题。

epoll的提升:

本身没有最大并发连接的限制,仅受系统中进程能打开的最大文件数目限制;

效率提升:只有活跃的socket才会主动的去调用callback函数;

省去不必要的内存拷贝:epoll通过内核与用户空间mmap同一块内存实现。

epoll的数据结构:

//在epoll中,关键的数据结构epoll_event定义如下:

typedef****unionepoll_data {

void*ptr;

intfd;

__uint32_t u32;

__uint64_t u64;

} epoll_data_t;

structepoll_event {

__uint32_t events;/* Epoll events */

epoll_data_t data;/* User data variable */

};

intepoll_create(intsize);

intepoll_ctl(intepfd,intop,intfd,structepoll_event *event);

intepoll_wait(intepfd,structepoll_event *events,intmaxevents,inttimeout);

epoll的高效就在于,当我们调用epoll_ctl往里塞入百万个句柄时,epoll_wait仍然可以飞快的返回,并有效的将发生事件的句柄给我们用户。这是由于我们在调用epoll_create时,内核除了帮我们在epoll文件系统里建了个file结点,在内核cache里建了个红黑树用于存储以后epoll_ctl传来的socket外,还会再建立一个list链表,用于存储准备就绪的事件,当epoll_wait调用时,仅仅观察这个list链表里有没有数据即可。有数据就返回,没有数据就sleep,等到timeout时间到后即使链表没数据也返回。所以,epoll_wait非常高效。

那么,这个准备就绪list链表是怎么维护的呢?当我们执行epoll_ctl时,除了把socket放到epoll文件系统里file对象对应的红黑树上之外,还会给内核中断处理程序注册一个回调函数,告诉内核,如果这个句柄的中断到了,就把它放到准备就绪list链表里。所以,当一个socket上有数据到了,内核在把网卡上的数据copy到内核中后就来把socket插入到准备就绪链表里了。

如此,一颗红黑树,一张准备就绪句柄链表,少量的内核cache,就帮我们解决了大并发下的socket处理问题。执行epoll_create时,创建了红黑树和就绪链表,执行epoll_ctl时,如果增加socket句柄,则检查在红黑树中是否存在,存在立即返回,不存在则添加到树干上,然后向内核注册回调函数,用于当中断事件来临时向准备就绪链表中插入数据。执行epoll_wait时立刻返回准备就绪链表里的数据即可。

图片

epoll支持水平触发和边缘触发,

**水平触发:**是当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据一次性全部读写完(如读写缓冲区太小),那么下次调用 epoll_wait()时,它还会通知你在上没读写完的文件描述符上继续读写,当然如果你一直不去读写,它会一直通知你!!!如果系统中有大量你不需要读写的就绪文件描述符,而它们每次都会返回,这样会大大降低处理程序检索自己关心的就绪文件描述符的效率!!!(水平触发看缓冲区大小和是否有数据来)

**边缘触发:**当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据全部读写完(如读写缓冲区太小),下次调用epoll_wait()时,它不会通知你,也就是它只会通知你一次,直到该文件描述符上出现第二次可读写事件才会通知你!!!这种模式比水平触发效率高,系统不会充斥大量你不关心的就绪文件描述符!!(边缘触发看是否有下一次事件)

边缘触发可能造成饥饿

用边缘触发处理,对一次事件,必须把数据全部读取完,不然下一次就读取不到了,如果这个数据过多,就会导致其他套接字饥饿。

3.linux零拷贝

传统IO(read() write())

图片

mmap() 共享内核空间的缓存。

图片

sendfile()

图片

图片

sendfile只适用于将数据从文件拷贝到套接字上,限定了它的使用范围。之后,linux还提出了splice,splice()调用在两个文件描述符之间移动数据,splice()调用利用了Linux提出的管道缓冲区机制,所以至少一个描述符要为管道。

4.linux硬链接和软连接

软链接文件,1.就是记录了另一个文件的路径名。可以是任意文件或目录,可以链接不同文件系统(因为就是路径名,和文件系统组织无关)的文件。

硬链接就是一个文件(只能是文件)的一个或多个文件名。把文件名和系统使用的节点号inode链接起来。可以用多个文件名与同一个文件硬链接。

硬链接只能对已存在的文件进行创建。硬链接的创建时间和原文件时间一样

硬链接创建:

link oldfile newfile

lnoldfile newfile

软连接:

link -s oldfile/dir newfile/dir

ln-soldfile/dir newfile/dir

删除一个有硬链接的文件后,磁盘文件空间不会被删除,因为引用计数,发现inode号还被硬链接引用着。但是这个文件的软链接不能用了,因为原文件的路径找不到了,变成死链接。但是我们向软连接写入数据,会重新创建一个文件,新文件和之前的硬链接指向的就不是同一块磁盘地址了

测试:

touch myfile && echo “This is a plain text file.” > myfile

cat myfile #This is a plain text file.

ln myfile hard

ls -li #输出文件inode和权限,发现权限前面没有l。

echo “New line” >> hard

cat myfile

#This is a plain text file.

#New line

ln -s myfile soft

ls -li #软连接权限前面有一个l。软连接inode号不一样

rm myfile

cat hard #删除原文件,硬链接正常输出

#This is a plain text file.

#New line

cat soft #文件不存在,找不到路径了

echo “Something” >> soft

ls -li #又出现了,软连接重新创建了一个文件,这个文件和硬链接的文件不是同一个。

5.协程

协程,是在应用层模拟的线程,他避免了上下文切换的额外耗费,兼顾了多线程的优点。简化了高并发程序的复杂度。

协程是基于线程的。go内部实现上,维护了一组数据结构和 n 个线程,真正的执行还是线程,协程执行的代码被扔进一个待执行队列中,由这 n 个线程从队列中拉出来执行。

6.孤儿进程和僵尸进程

孤儿进程:父进程结束了,而它的一个或多个子进程还在运行,那么这些子进程就成为孤儿进程(father died)。子进程的资源由init进程(进程号PID = 1)回收。

僵尸进程:子进程退出了,但是父进程没有用wait或waitpid去获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中,这种进程称为僵死进程。

系统所能使用的进程号是有限的。僵尸进程无法用kill直接杀死。

7.软中断和硬中断

中断是一种电信号,当设备有某种事件发生时,它就会产生中断,通过总线把电信号发送给中断控制器。

(1) 硬中断

由与系统相连的外设(比如网卡、硬盘)自动产生的。主要是用来通知操作系统系统外设状态的变化。比如当网卡收到数据包的时候,就会发出一个中断。我们通常所说的中断指的是硬中断。

(2)软中断

为了满足实时系统的要求,中断处理应该是越快越好。linux为了实现这个特点,当中断发生的时候,硬中断处理那些短时间就可以完成的工作,而将那些处理事件比较长的工作,放到中断之后来完成,也就是软中断来完成。

软中断并不会直接中断CPU。也只有当前正在运行的代码(或进程)才会产生软中断。这种中断是一种需要内核为正在运行的进程去做一些事情(通常为I/O)的请求。有一个特殊的软中断是Yield调用,它的作用是请求内核调度器去查看是否有一些其他的进程可以运行。

软中断不能嵌套,但相同类型的软中断可以在不同CPU上并行执行。

8.Linux常用命令

1
tcpdump -i eth0   // 抓包命令

九、计算机网络

1.TCP 协议如何保证可靠传输

1、消息确认和重传

2、数据校验

3、数据合理分片和排序

每种数据链路的最大传输单元 MTU 都是不相同的,以太网的 MTU 是

1500 字节等。以太网最大数据负载是1500字节, ip头部20字节,tcp头部20字节,所以tcp最大数据负载1460字节。

TCP 引入了 MSS(最大报文段长度),就说应用层整个的大小。

4、流量控制:当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。

5、拥塞控制:当网络拥塞时,减少数据的发送。慢开始,拥塞避免,快重传,快恢复。

图片

2.UDP一次发送多少字节最好?

  1. 从MTU角度看

以太网数据链路层的数据区MTU最大1500字节,那么一次udp最大数据包为1472字节。减去IP头20字节,UDP头8字节。

  1. 从IP封包总长度看

在IP头中,头部总长度字段规定封包总长度为 2 bytes也就是一个IP包最多长度为65535个,这样减去一个IP头,再减一个UDP头就是65535- 20 - 8 = 65507个。

总结

从上面两个来看,UDP编程时最好不要超过1472(针对以太网),如果要求不高,就算超过了1472,也不可以超过65507,即包总大小不要超过64k。

TCP以此类推?TCP头部20字节。

TCP中MSS最大为1460字节,减去20字节IP头,减去20字节TCP头。

如果再去掉TCP选项可能有12字节,那最大数据为1448字节。

3.流量控制

主要通过滑动窗口

协议:停止等待协议,回退N协议,选择重传协议。

4.TLS1.2和TLS1.3

https://blog.csdn.net/mrpre/article/details/81532469

TLS1.2

图片

1.客户端发送ClientHello消息,该消息中主要包括客户端支持的协议版本、加密套件列表及握手过程需要用到的ECC扩展信息;

2.服务端回复ServerHello,包含选定的加密套件和ECC扩展;发送证书给客户端;选用客户端提供的参数生成ECDH临时公钥,同时回复ServerKeyExchange消息;

3.客户端接收ServerKeyExchange后,使用证书公钥进行签名验证,获取服务器端的ECDH临时公钥,生成会话所需要的共享密钥;生成ECDH临时公钥和ClientKeyExchange消息发送给服务端;

4.服务器处理ClientKeyExchange消息,获取客户端ECDH临时公钥;服务器生成会话所需要的共享密钥;发送密钥协商完成消息给客户端;

双方使用生成的共享密钥对消息加密传输,保证消息安全。

TLS1.3

图片

1.客户端发送ClientHello消息,该消息主要包括客户端支持的协议版本、DH密钥交换参数列表KeyShare;

2.服务端回复ServerHello,包含选定的加密套件;发送证书给客户端;使用证书对应的私钥对握手消息签名,将结果发送给客户端;选用客户端提供的参数生成ECDH临时公钥,结合选定的DH参数计算出用于加密HTTP消息的共享密钥;服务端生成的临时公钥通过KeyShare消息发送给客户端;

3.客户端接收到KeyShare消息后,使用证书公钥进行签名验证,获取服务器端的ECDH临时公钥,生成会话所需要的共享密钥;

双方使用生成的共享密钥对消息加密传输,保证消息安全。

十、Redis

1.Redis缓存穿透,缓存击穿,缓存雪崩

缓存穿透的概念很简单,当高并发查询一个不存在的数据时,在缓存中都没有命中,于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透。

解决:1.使用布隆过滤器 2.缓存空对象

缓存击穿,是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。

解决:1. 设置热点数据"永不过期" 2.设置锁,只让一个线程去访问数据库,先缓存起来,之后其他的线程直接从缓存中取。

缓存雪崩是指,缓存层出现了错误,不能正常工作了。于是所有的请求都会达到存储层,存储层的调用量会暴增,造成存储层也会挂掉的情况。

解决:1.redis高可用,集群,哨兵 2.限流降级 3.数据预热,在即将发生大并发访问之前 手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

2.Redis为什么快?

1.Redis完全基于内存操作,数据缓存在内存中。Redis的瓶颈是机器内存访问速度和网络带宽。Redis的高效的数据结构(ziplist.skiplist)

Redis的IO的单线程模型,多路复用。

2.Redis基于Reactor模式开发了自己的网络事件处理器,被称为文件事件处理器,由套接字、I/O多路复用程序、文件事件分派器(dispatcher),事件处理器四部分组成。

图片

3.单线程避免了线程切换和竞态产生的消耗。

  1. 多路 I/O 复用技术可以让单个线程高效的处理多个连接请求。I/O多路复用程序会同时监听多个套接字,当被监听的套接字准备好执行accept、read、write、close等操作时,与操作相对应的文件事件就会产生,I/O多路复用程序会将所有产生事件的套接字都压入一个队列,然后以有序地每次仅一个套接字的方式传送给文件事件分派器,文件事件分派器接收到套接字后会根据套接字产生的事件类型调用对应的事件处理器。

3.先更新数据库还是先更新缓存?

MySQL处理实时性数据,例如金融数据、交易数据。

Redis处理实时性要求不高的数据,例如网站最热贴排行榜,好友列表等。

在并发不高的情况下,读操作优先读取redis,不存在的话就去访问MySQL,并把读到的数据写回Redis中;写操作的话,直接写MySQL,成功后再写入Redis(可以在MySQL端定义CRUD触发器,在触发CRUD操作后写数据到Redis,也可以在Redis端解析binlog,再做相应的操作)。

在并发高的情况下,读操作和上面一样,写操作是异步写,写入Redis后直接返回,然后定期写入MySQL。

4.RDB和aof

1.rdb

rdb文件都是二进制,很小。

  1. save命令同步、阻塞 致命的问题,持久化时redis服务阻塞,不能对外提供服务。

  2. bgsave异步、非阻塞 fork() + copyonwrite 边持久化,边对外提供读写服务,互不影响,新写的数据对我持久化不会造成数据影响,你持久化的过程中报错或者耗时太久都对我当前对外提供请求的服务不会产生任何影响。持久化完会将新的rdb文件覆盖之前的。

2.aof

aof记录每一条创建修改命令,先将命令写道缓冲区中,再根据配置的aof持久化时间策略,持久化到aof文件中。文件是文本文件,较大。同样是fork()子进程执行。

十一、简单算法

  1. 判断链表环的问题

判断链表是否有环?

直接利用快慢指针,一个走fast->next->next,一个走slow->next.在一圈以内可相遇。

求环的节点数?

从相遇节点开始,一个指针一个指针走,再回到相遇节点就知道环的节点数了。

求环的入口?

1.直接用hashset,第一次判断重复的点就是入口。2.从起点开始和从相遇点开始,每次走一步,再次相遇为入口。

十二、分布式

  1. 一致性hash算法

图片

服务器太少,可以增加虚拟节点来扩撒分布,虚拟节点和真实的节点映射。

十三、Spring

  1. Springboot启动过程

图片

new SpringApplication()检查web环境,根据WebApplicationType中NONE,SERVLET,REACTIVE;设置初始化器,监听器。配置主方法所在类。

run()起来后,启动计时器监听器。创建配置环境,创建上下文对象,更新应用上下文。一边在监听器中获取工厂,通过工厂生成bean。另一边自动配置,在spring.factories中获取自动配置相关的类名,反射创建类。在refreshContext(),会创建tomcat等web服务器并启动。

最后执行apprunner和commandrunner.

2.spring整合mybatis

非事务: 每次操作数据库都使用新的sqlSession对象。因此mybatis的一级缓存无法使用(一级缓存针对同一个sqlsession有效)

开启事物后:spring使用ThreadLocal获取当前资源绑定同一个sqlSession,因此此时一级缓存是有效的

在开启以及缓存的时候查询得到的对象是同一个对象。

二级缓存需要手动开启和配置,是基于namespace级别的缓存。

提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存

1
2
3
4
<settings>
<!-- 对在此配置文件下的所有cache进行全局性的开/关设置。默认值:true -->
<setting name="cacheEnabled" value="true"/>
</settings>
1
2
3
4
5
<!--在当前Mapper.xml中使用二级缓存-->
<cache eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>

增删改操作,无论是否进行提交commit(),均会清空一级、二级缓存。

**3.@Autowired 与@Resource****和@**Inject

@Autowired默认按类型装配(这个注解是属业spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false.

@Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。

@Inject这是jsr330中的规范,通过’AutowiredAnnotationBeanPostProcessor’类实现的依赖注入. 不加@Named注解, 需要配置与变量名一致.

4.循环依赖

Spring的循环依赖的理论依据其实是基于Java的引用传递,当我们获取到对象的引用时,对象的field或则属性是可以延后设置的(但是构造器必须是在获取引用之前)。

Spring的单例对象的初始化主要分为三步:先实例化,再设置属性,最后调用自定义的初始化方法。

spring三级缓存:

1.singletonFactories : 单例对象工厂的cache

2.earlySingletonObjects :提前暴光的单例对象的Cache

3.singletonObjects:单例对象的cache

5.bean生命周期

图片

丢失修改

、JDK源码Bug

  1. jdk8的JDBC中的Bug

JDK8中DriverManager中使用static块来初始化驱动,但是Prinln打印函数是调用logWriter对象(PrintWriter)来打印日志,但是这个对象一开始是null的,所以这句话永远输出不了。但是JDK11已经改了,在getConnection()中初始化驱动,那么在调用这个函数之前设置PrintWriter对象就可以了。

1
2
3
4
static {
loadInitialDrivers();
println("JDBC DriverManager initialized");
}

61.为什么要使用克隆?

答:当需要对一个对象进行处理,同时又想保留原有的数据进行接下来的操作,就需要使用克隆。

62.如何实现对象克隆?

答:

有两种方式:

1). 实现Cloneable接口并重写Object类中的clone()方法;

2). 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。

63.深拷贝和浅拷贝区别是什么?

答:

浅拷贝:复制基本类型的属性;引用类型的属性复制,复制栈中的变量和变量指向堆内存中的对象的指针,不复制堆内存中的对象。

深拷贝:复制基本类型的属性;引用类型的属性复制,复制栈中的变量和变量指向堆内存中的对象的指针和堆内存中的对象。

、Java Web

1.过滤器和拦截器

图片

图片

过滤器:基于函数回调,过滤器链模式。

拦截器:基于反射原理,是AOP面向切面编程。

、Zookeeper

1.Zookeeper有什么用

(1)元数据/配置信息管理

主要做很多系统的配置信息的管理,注册中心。

(2)分布式协调

作为一个协调者,协调多个服务。

(3)分布式锁

A创建一个节点,B不能创建了充当锁得作用;只有A删除节点,B才能获得锁。

(4)高可用系统

做主备。

十七、Kafka

1.Kafka副本机制

Kafka 的主题被分为多个分区 ,分区是 Kafka 最基本的存储单位**。每个分区可以有多个副本**(可以在创建主题时使用replication-factor参数进行指定)。其中一个副本是首领副本 (Leader replica),所有的事件都直接发送给首领副本;其他副本是跟随者副本 (Follower replica),需要通过复制来保持与首领副本数据一致,当首领副本不可用时,其中一个跟随者副本将成为新首领。

每个分区都有一个ISR(in-sync Replica) 列表,用于维护所有同步的、可用的副本。首领副本必然是同步副本,而对于跟随者副本来说,它需要满足以下条件才能被认为是同步副本:

  • 与 Zookeeper 之间有一个活跃的会话,即必须定时向 Zookeeper 发送心跳;
  • 在规定的时间内从首领副本那里低延迟地获取过消息。

如果副本不满足上面条件的话,就会被从 ISR 列表中移除,直到满足条件才会被再次加入。

十八、场景题

1.防止超卖问题

(1)悲观锁,所有修改操作都加上锁。

(2)乐观锁,先都获取版本号,然后修改数据带上版本号,如果版本被其中一个线程改了,其他线程就会失败。

(3)redis预先缓存,因为redis修改数据是单线程的,所以减少到0了,拒绝其他线程,其它线程就不能再减了

(4)redis分布式锁,zookeeper分布式锁。

2.appid、appkey、appsecret(OAuth******2.0)**

app_key 和 app_secret 是一对出现的账号, 同一个 app_id 可以对应多个 app_key+app_secret, 平台就可以分配你不一样的权限, 比如 app_key1 + app_secect1 只有只读权限, 但是 app_key2+app_secret2 有读写权限… 就可以把对应的权限放给不同的开发者. 其中权限的配置都是直接跟app_key 做关联的, app_key 也需要添加数据库检索, 方便快速查找。

根据他们来申请一个token, 就是我们经常用到的 access_token。

令牌token是由一组信息(json对象)和公钥加密而来的,比如请求人姓名、系统信息、IP、浏览器信息等等。然后后端获取到token并结合私钥可以解密得到所有信息并核对。所以你复制了别人token去请求是没用的,除非你拥有产生令牌一样的网络环境,比如相同IP、相同系统、相同浏览器等等。

3.二维码登录原理

1.pc生成二维码

图片

2.手机扫描二维码

图片

3.状态确认

图片

十九、设计模式

1.工厂模式

工厂模式是为了解耦:把对象的创建和使用的过程分开。

工厂模式可以降低代码重复。如果创建对象B的过程都很复杂,需要一定的代码量,而且很多地方都要用到,那么就会有很多的重复代码。我们可以这些创建对象B的代码放到工厂里统一管理。既减少了重复代码,也方便以后对B的创建过程的修改维护。

数据库工厂:可以返回一个数据库实例,可以是mysql,oracle等。

这个工厂就可以把数据库连接需要的用户名,地址,密码等封装好,直接返回对应的数据库对象就好。不需要调用者自己初始化,减少了写错密码等等这些错误。调用者只负责使用,不需要管怎么去创建、初始化对象。

如BeanFactory.

64.jsp 和 servlet 有什么区别?

65.jsp 有哪些内置对象?作用分别是什么?

66.说一下 jsp 的 4 种作用域?

67.session 和 cookie 有什么区别?

68.说一下 session 的工作原理?

69.如果客户端禁止 cookie 能实现 session 还能用吗?

70.spring mvc 和 struts 的区别是什么?

71.如何避免 sql 注入?

72.什么是 XSS 攻击,如何避免?

73.什么是 CSRF 攻击,如何避免?

七、异常

74.throw 和 throws 的区别?

75.final、finally、finalize 有什么区别?

76.try-catch-finally 中哪个部分可以省略?

try catch /try finally

77.try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?

78.常见的异常类有哪些?

八、网络

79.http 响应码 301 和 302 代表的是什么?有什么区别?

都表示重定向

301 redirect: 301 代表永久性转移(Permanently Moved)

302 redirect: 302 代表暂时性转移(Temporarily Moved )

301表示旧地址A的资源已经被永久地移除了(这个资源不可访问了),搜索引擎在抓取新内容的同时也将旧的网址交换为重定向之后的网址;302表示旧地址A的资源还在(仍然可以访问),这个重定向只是临时地从旧地址A跳转到地址B,搜索引擎会抓取新的内容而保存旧的网址。

80.forward 和 redirect 的区别?

81.简述 tcp 和 udp的区别?

82.tcp 为什么要三次握手,两次不行吗?为什么?

83.说一下 tcp 粘包是怎么产生的?

84.OSI 的七层模型都有哪些?

85.get 和 post 请求有哪些区别?

86.如何实现跨域?

87.说一下 JSONP 实现原理?

九、设计模式

88.说一下你熟悉的设计模式?

89.简单工厂和抽象工厂有什么区别?

十、Spring/Spring MVC

90.为什么要使用 spring?

91.解释一下什么是 aop?

92.解释一下什么是 ioc?

93.spring 有哪些主要模块?

94.spring 常用的注入方式有哪些?

95.spring 中的 bean 是线程安全的吗?

96.spring 支持几种 bean 的作用域?

97.spring 自动装配 bean 有哪些方式?

98.spring 事务实现方式有哪些?

99.说一下 spring 的事务隔离?

100.说一下 spring mvc 运行流程?

101.spring mvc 有哪些组件?

102.@RequestMapping 的作用是什么?

103.@Autowired 的作用是什么?

十一、Spring Boot/Spring Cloud

104.什么是 spring boot?

105.为什么要用 spring boot?

106.spring boot 核心配置文件是什么?

107.spring boot 配置文件有哪几种类型?它们有什么区别?

108.spring boot 有哪些方式可以实现热部署?

109.jpa 和 hibernate 有什么区别?

110.什么是 spring cloud?

111.spring cloud 断路器的作用是什么?

112.spring cloud 的核心组件有哪些?

十二、Hibernate

113.为什么要使用 hibernate?

114.什么是 ORM 框架?

115.hibernate 中如何在控制台查看打印的 sql 语句?

116.hibernate 有几种查询方式?

117.hibernate 实体类可以被定义为 final 吗?

118.在 hibernate 中使用 Integer 和 int 做映射有什么区别?

119.hibernate 是如何工作的?

120.get()和 load()的区别?

121.说一下 hibernate 的缓存机制?

122.hibernate 对象有哪些状态?

123.在 hibernate 中 getCurrentSession 和 openSession 的区别是什么?

124.hibernate 实体类必须要有无参构造函数吗?为什么?

十三、Mybatis

125.mybatis 中 #{}和 ${}的区别是什么?

126.mybatis 有几种分页方式?

127.RowBounds 是一次性查询全部结果吗?为什么?

128.mybatis 逻辑分页和物理分页的区别是什么?

129.mybatis 是否支持延迟加载?延迟加载的原理是什么?

130.说一下 mybatis 的一级缓存和二级缓存?

131.mybatis 和 hibernate 的区别有哪些?

132.mybatis 有哪些执行器(Executor)?

133.mybatis 分页插件的实现原理是什么?

134.mybatis 如何编写一个自定义插件?

十四、RabbitMQ

135.rabbitmq 的使用场景有哪些?

136.rabbitmq 有哪些重要的角色?

137.rabbitmq 有哪些重要的组件?

138.rabbitmq 中 vhost 的作用是什么?

139.rabbitmq 的消息是怎么发送的?

140.rabbitmq 怎么保证消息的稳定性?

141.rabbitmq 怎么避免消息丢失?

142.要保证消息持久化成功的条件有哪些?

143.rabbitmq 持久化有什么缺点?

144.rabbitmq 有几种广播类型?

145.rabbitmq 怎么实现延迟消息队列?

146.rabbitmq 集群有什么用?

147.rabbitmq 节点的类型有哪些?

148.rabbitmq 集群搭建需要注意哪些问题?

149.rabbitmq 每个节点是其他节点的完整拷贝吗?为什么?

150.rabbitmq 集群中唯一一个磁盘节点崩溃了会发生什么情况?

151.rabbitmq 对集群节点停止顺序有要求吗?

十五、Kafka

152.kafka 可以脱离 zookeeper 单独使用吗?为什么?

kafka 不能脱离 zookeeper 单独使用, 因为 kafka 使用 zookeeper 管理和协调 kafka 的节点服务器broker,管理主题topic。

153.kafka 有几种数据保留的策略?

kafka 有两种数据保存策略:按照过期时间保留和按照存储的消息大小保留。

154.kafka 同时设置了 7 天和 10G 清除数据,到第五天的时候消息达到了 10G,这个时候 kafka 将如何处理?

155.什么情况会导致 kafka 运行变慢?

cpu性能瓶颈 磁盘读写瓶颈 网络瓶颈

156.使用 kafka 集群需要注意什么?

十六、Zookeeper

157.zookeeper 是什么?

158.zookeeper 都有哪些功能?

159.zookeeper 有几种部署模式?

160.zookeeper 怎么保证主从节点的状态同步?

161.集群中为什么要有主节点?

162.集群中有 3 台服务器,其中一个节点宕机,这个时候 zookeeper 还可以使用吗?

163.说一下 zookeeper 的通知机制?

十七、MySql

164.数据库的三范式是什么?

165.一张自增表里面总共有 7 条数据,删除了最后 2 条数据,重启 mysql 数据库,又插入了一条数据,此时 id 是几?

166.如何获取当前数据库版本?

167.说一下 ACID 是什么?

168.char 和 varchar 的区别是什么?

169.float 和 double 的区别是什么?

170.mysql 的内连接、左连接、右连接有什么区别?

171.mysql 索引是怎么实现的?

172.怎么验证 mysql 的索引是否满足需求?

173.说一下数据库的事务隔离?

174.说一下 mysql 常用的引擎?

175.说一下 mysql 的行锁和表锁?

176.说一下乐观锁和悲观锁?

177.mysql 问题排查都有哪些手段?

178.如何做 mysql 的性能优化?

十八、Redis

179.redis 是什么?都有哪些使用场景?

180.redis 有哪些功能?

181.redis 和 memecache 有什么区别?

182.redis 为什么是单线程的?

183.什么是缓存穿透?怎么解决?

184.redis 支持的数据类型有哪些?

185.redis 支持的 java 客户端都有哪些?

186.jedis 和 redisson 有哪些区别?

187.怎么保证缓存和数据库数据的一致性?

188.redis 持久化有几种方式?

189.redis 怎么实现分布式锁?

190.redis 分布式锁有什么缺陷?

191.redis 如何做内存优化?

192.redis 淘汰策略有哪些?

193.redis 常见的性能问题有哪些?该如何解决?

十九、JVM

194.说一下 jvm 的主要组成部分?及其作用?

195.说一下 jvm 运行时数据区?

196.说一下堆栈的区别?

197.队列和栈是什么?有什么区别?

198.什么是双亲委派模型?

199.说一下类加载的执行过程?

200.怎么判断对象是否可以被回收?

201.java 中都有哪些引用类型?

202.说一下 jvm 有哪些垃圾回收算法?

203.说一下 jvm 有哪些垃圾回收器?

204.详细介绍一下 CMS 垃圾回收器?

205.新生代垃圾回收器和老生代垃圾回收器都有哪些?有什么区别?

206.简述分代垃圾回收器是怎么工作的?

207.说一下 jvm 调优的工具?

208.常用的 jvm 调优的参数都有哪些?

观察者模式

观察者模式(Observer Pattern):定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式是一种对象行为型模式。

阅读全文 »

UML类图学习

类与类之间的关系可以简单的分为:泛化,实现,聚合,组合,依赖,关联。

阅读全文 »

ThreadLocalRandom

Random 生成新的随机数需要两步:

  • 根据老的 seed 生成新的 seed
  • 由新的 seed 计算出新的随机数
阅读全文 »

TCP三次握手和四次挥手

为什么要三次握手

谢希仁著《计算机网络》第四版中讲“三次握手”的目的是“为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误”。防止了服务器端的一直等待而浪费资源。在另一部经典的《计算机网络》一书中讲“三次握手”的目的是为了解决“网络中存在之前的延迟的重复分组”的问题。

阅读全文 »

JVM学习

JVM参数

-Xms 设定java程序启动时占用堆内存大小,大则启动快
-Xmx 程序运行期间最大可用堆内存,超出了抛出OutOfMemory异常
-Xss 每个线程的堆栈大小
-Xmn 年轻代的大小

阅读全文 »

HTTP和HTTPS

HTTP

HTTP 由于是明文传输,主要存在三大风险:窃听风险、篡改风险、冒充风险
安全的通信需要包括以下四个原则: 机密性、完整性,身份认证和不可否认。
不可否认:不否认已经发生的行为。

阅读全文 »

二进制安全的String类型

二进制安全是指,在传输数据时,保证二进制数据的信息安全,也就是不被篡改、破译等,如果被攻击,能够及时检测出来。
有的程序会将某些特殊的二进制串作为标志符,如果二进制数据里面恰好就包含了这种标志符,那么程序要能够正确识别解析二进制文件,而不是出错。
二进制安全包含了密码学的一些东西,比如加解密、签名等。

阅读全文 »